import { DeviceSource } from "@babylonjs/core/DeviceInput/InputDevices/deviceSource";
import { DeviceInputKey, InputStatus } from "./device-information";
import { DeviceType } from "@babylonjs/core/DeviceInput/InputDevices/deviceEnums";
import { DeviceInput } from "@babylonjs/core/DeviceInput/InputDevices/deviceTypes";
import { CreateHandleTo, IHandle, RemoveHandle } from '../../data/data-handle';


/**
 * 输入键对象参数对象
 * @param pressThreshold 按住的时长阈值（当按住时间不小于此值时，识别为press，而不是click）
 */
interface IInputKeyStatusOptions {
    pressThreshold?: number,
}


/**
 * @internal
 * 输入键对象
 * @param key 输入键
 * @param index 输入键索引
 * @param device 设备源
 * @param options 参数对象
 */
class InputKeyStatus<T extends DeviceType>{

    private _time: number = 0;
    private _duration: number = 0;
    private _status: InputStatus = InputStatus.none;
    private _options: IInputKeyStatusOptions;
    private _downHandles: IHandle<void>[] = [];
    private _clickHandles: IHandle<void>[] = [];
    private _pressHandles: IHandle<void>[] = [];
    private _upHandles: IHandle<void>[] = [];

    /**
     * 输入键
     */
    public readonly key: DeviceInputKey;
    /**
     * 输入键索引
     */
    public readonly index: DeviceInput<T>;
    /**
     * 设备源
     */
    public readonly device: DeviceSource<T>;

    constructor(key: DeviceInputKey, index: DeviceInput<T>, device: DeviceSource<T>, options?: IInputKeyStatusOptions) {
        this.key = key;
        this.index = index;
        this.device = device;
        const ops = options || {};
        ops.pressThreshold = ops.pressThreshold || 500;
        this._options = ops;
    }

    /**
     * 获取当前状态
     */
    public get status():InputStatus{
        return this._status;
    }

    /**
     * 是否为空闲状态（没有响应的回调函数）
     */
    public get isIdle(): boolean {
        return !(this._downHandles.length || this._upHandles.length || this._clickHandles.length || this._pressHandles.length);
    }

    /**
     * 添加按下时的回调函数对象
     * @param callback 回调函数
     * @returns 回调函数对象
     */
    public onDown(callback: { (): void }): IHandle<void> {
        return CreateHandleTo<void>(callback, this._downHandles);
    }

    /**
     * 移除按下时的回调函数对象
     * @param handle 回调函数对象或其id
     */
    public removeDownHandle(handle: IHandle<void> | number): void {
        RemoveHandle(handle, this._downHandles);
    }

    /**
     * 添加点击时的回调函数对象
     * @param callback 回调函数
     * @returns 回调函数对象
     */
    public onClick(callback: { (): void }): IHandle<void> {
        return CreateHandleTo<void>(callback, this._clickHandles);
    }

    /**
     * 移除点击时的回调函数对象
     * @param handle 回调函数对象或其id
     */
    public removeClickHandle(handle: IHandle<void> | number): void {
        RemoveHandle(handle, this._clickHandles);
    }

    /**
     * 添加按住时的回调函数对象
     * @param callback 回调函数
     * @returns 回调函数对象
     */
    public onPress(callback: { (): void }): IHandle<void> {
        return CreateHandleTo<void>(callback, this._pressHandles);
    }

    /**
     * 移除按住时的回调函数对象
     * @param handle 回调函数对象或其id
     */
    public removePressHandle(handle: IHandle<void> | number): void {
        RemoveHandle(handle, this._pressHandles);
    }

    /**
     * 添加抬起时的回调函数对象
     * @param callback 回调函数
     * @returns 回调函数对象
     */
    public onUp(callback: { (): void }): IHandle<void> {
        return CreateHandleTo<void>(callback, this._upHandles);
    }

    /**
     * 移除抬起时的回调函数对象
     * @param handle 回调函数对象或其id
     */
    public removeUpHandle(handle: IHandle<void> | number): void {
        RemoveHandle(handle, this._upHandles);
    }

    /**
     * 检测当前输入状态
     */
    public check(): void {
        let success=true;
        let state=0;
        try{
            state=this.device.getInput(this.index);
        }catch(err){
            success=false;
        }
        if(!success)return;
        if (state === 1) {
            switch (this._status) {
                case InputStatus.none: case InputStatus.up: case InputStatus.click:
                    this._time = performance.now();
                    this._duration = 0;
                    this._status = InputStatus.down;
                    this._downHandles.forEach(h => h.callback());
                    break;
                case InputStatus.down:
                    let cur = performance.now();
                    this._duration += cur - this._time;
                    if (this._duration >= this._options.pressThreshold!) {
                        this._status = InputStatus.press;
                        this._pressHandles.forEach(h => h.callback());
                    }
                    this._time = cur;
                    break;
                case InputStatus.press:
                    cur = performance.now();
                    this._duration += cur - this._time;
                    this._time = cur;
                    break;
            }
        } else {
            switch (this._status) {
                case InputStatus.down:
                    this._status = InputStatus.click;
                    this._clickHandles.forEach(h => h.callback());
                    break;
                case InputStatus.click: case InputStatus.press:
                    this._status = InputStatus.up;
                    this._upHandles.forEach(h => h.callback());
                    break;
                case InputStatus.up:
                    this._status = InputStatus.none;
                    this._time = 0;
                    this._duration = 0;
                    break;
            }
        }
    }

    /**
     * 重置输入状态
     */
    public reset(): void {
        this._status = InputStatus.none;
        this._time = 0;
        this._duration = 0;
    }

}


export { InputKeyStatus };
export type { IInputKeyStatusOptions };